﻿using System;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Markup;

namespace Orz.Framework.Foundation.Converters
{
    /// <summary>
    /// If the Converter's return type is boolean or boolean?, it'll invert the result.
    /// </summary>
    [DefaultProperty("Converter")]
    [ContentProperty("Converter")]
    public class NotBooleanConverter : IValueConverter
    {
        /// <summary>
        /// Gets or sets the converter.
        /// </summary>
        /// <value>The converter.</value>
        public IValueConverter Converter { get; set; }

        #region IValueConverter Members

        /// <summary>
        /// Converts a value.
        /// </summary>
        /// <param name="value">The value produced by the binding source.</param>
        /// <param name="targetType">The type of the binding target property.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        /// A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return GetNotBooleanResult(Converter.Convert(value, targetType, parameter, culture));
        }

        /// <summary>
        /// Converts a value.
        /// </summary>
        /// <param name="value">The value that is produced by the binding target.</param>
        /// <param name="targetType">The type to convert to.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        /// A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return GetNotBooleanResult(Converter.ConvertBack(value, targetType, parameter, culture));
        }

        #endregion

        /// <summary>
        /// Gets the not boolean result.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        private bool GetNotBooleanResult(object result)
        {
            if (Converter != null)
            {
                if (result is bool)
                    return !(bool)result;
                else if (result is bool?)
                {
                    bool? temp = (bool?)result;
                    if (temp == null)
                        return true;
                    else
                        return !temp.Value;
                }
                else
                    throw new NotSupportedException("NotBooleanConverter limit the value type must be bool or Nullable<bool>.");
            }
            throw new NotSupportedException("The InnerConverter of NotBooleanConverter can't be null.");
        }
    }
}
